package com.yxf.radarview;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.SweepGradient;
import android.os.Message;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.animation.LinearInterpolator;

import com.yxf.usefullib.MySurfaceView;
import com.yxf.usefullib.WeakHandler;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class RadarView extends MySurfaceView {

    private static final int MESSAGE_START_ANIMATOR = 1;
    private static final int MESSAGE_CANCEL_ANIMATOR = 2;


    private int mSize;
    private int mScanPeriod;
    private int mPadding;
    private int mCenterX, mCenterY;
    private int mRadius;
    private int mWidth, mHeight;

    private Paint mBackgroundCirclePaint = new Paint();
    private int mBackgroundCircleColor = getResources().getColor(android.R.color.holo_blue_dark);

    private Paint mRingPaint = new Paint();
    private int mRingColor = Color.WHITE;

    private Paint mCrossPaint = new Paint();
    private int mCrossColor = Color.WHITE;

    private Paint mScanPaint = new Paint();

    private List<ColorPosition> mColorPositionList = new ArrayList<>();

    private float mScanDegree;

    private ValueAnimator mScanAnimator;

    public RadarView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initialize();
    }

    public RadarView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize();
    }


    public RadarView(Context context) {
        super(context);
        initialize();
    }

    private void initialize() {
        mBackgroundCirclePaint.setColor(mBackgroundCircleColor);

        mRingPaint.setColor(mRingColor);
        mRingPaint.setStrokeWidth(2);
        mRingPaint.setStyle(Paint.Style.STROKE);
        mRingPaint.setAntiAlias(true);

        mCrossPaint.setColor(mCrossColor);
        mCrossPaint.setStrokeWidth(2);
        mRingPaint.setAntiAlias(true);

        mBackgroundCirclePaint.setAntiAlias(true);

        mScanPaint.setAntiAlias(true);

        setScanPeriod(3000);
        setPadding(20);

    }

    @Override
    public void drawFrame(Canvas canvas) {
        super.drawFrame(canvas);
        drawBackgroundCircle(canvas);
        drawScanning(canvas);
        drawRing(canvas);
        drawCross(canvas);
    }


    private void drawScanning(Canvas canvas) {
        int[] colors;
        float[] positions;
        int size = mColorPositionList.size();
        if (size < 2) {
            return;
        }
        colors = new int[size];
        positions = new float[size];
        for (int i = 0; i < size; i++) {
            colors[i] = mColorPositionList.get(i).color;
            positions[i] = mColorPositionList.get(i).position;
        }
        SweepGradient gradient = new SweepGradient(mCenterX, mCenterY, colors, positions);
        mScanPaint.setShader(gradient);
        canvas.drawCircle(mCenterX, mCenterY, mRadius, mScanPaint);
    }

    private void drawBackgroundCircle(Canvas canvas) {
        canvas.drawCircle(mCenterX, mCenterY, mRadius, mBackgroundCirclePaint);
    }

    private void drawRing(Canvas canvas) {
        canvas.drawCircle(mCenterX, mCenterY, mRadius / 5 * 2, mRingPaint);
        canvas.drawCircle(mCenterX, mCenterY, mRadius / 5 * 4, mRingPaint);
    }

    private void drawCross(Canvas canvas) {
        canvas.drawLine(mCenterX, mCenterY - mRadius, mCenterX, mCenterY + mRadius, mCrossPaint);
        canvas.drawLine(mCenterX - mRadius, mCenterY, mCenterX + mRadius, +mCenterY, mCrossPaint);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        super.surfaceChanged(holder, format, width, height);
        this.mHeight = height;
        this.mWidth = width;
        initializeShapeProperties();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        super.surfaceCreated(holder);
        WeakHandler handler = getThreadHandler();
        handler.sendEmptyMessage(MESSAGE_START_ANIMATOR);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        WeakHandler handler = getThreadHandler();
        handler.sendEmptyMessage(MESSAGE_CANCEL_ANIMATOR);
        super.surfaceDestroyed(holder);
    }

    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case MESSAGE_START_ANIMATOR:
                mScanAnimator = ValueAnimator.ofInt(0, 360);
                mScanAnimator.setDuration(mScanPeriod);
                mScanAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        mScanDegree = (float) (Integer) animation.getAnimatedValue();
                        onScanDegreeChanged();
                    }
                });
                mScanAnimator.setInterpolator(new LinearInterpolator());
                mScanAnimator.setRepeatCount(ValueAnimator.INFINITE);
                mScanAnimator.start();
                return true;
            case MESSAGE_CANCEL_ANIMATOR:
                mScanAnimator.cancel();
                WeakHandler handler = getThreadHandler();
                handler.removeCallbacksAndMessages(null);
                return true;
        }
        return super.handleMessage(msg);
    }

    private void onScanDegreeChanged() {
        mColorPositionList.clear();
        mColorPositionList.add(new ColorPosition(getDegreePosition(mScanDegree), Color.WHITE));
        mColorPositionList.add(new ColorPosition(getDegreePosition(mScanDegree - 45), Color.argb(0x88, 0x00, 0xcc, 0x44)));
        mColorPositionList.add(new ColorPosition(getDegreePosition(mScanDegree - 225), mBackgroundCircleColor));
        mColorPositionList.add(new ColorPosition(getDegreePosition(mScanDegree - 225), Color.TRANSPARENT));
        mColorPositionList.add(new ColorPosition(getDegreePosition(mScanDegree - 359), Color.TRANSPARENT));
        Collections.sort(mColorPositionList, new Comparator<ColorPosition>() {
            @Override
            public int compare(ColorPosition o1, ColorPosition o2) {
                return o1.position - o2.position > 0f ? 1 : -1;
            }
        });
        ColorPosition start = mColorPositionList.get(mColorPositionList.size() - 1);
        ColorPosition end = mColorPositionList.get(0);
        int middleColor = getMiddleColor(start.color, end.color, (1 - start.position) / (1 + end.position - start.position));
        mColorPositionList.add(new ColorPosition(1f, middleColor));
        mColorPositionList.add(0, new ColorPosition(0f, middleColor));
        refresh();
    }

    private int getMiddleColor(int startColor, int endColor, float percent) {
        int a = getMiddleValue(startColor >> 24 & 0xff, endColor >> 24 & 0xff, percent);
        int r = getMiddleValue(startColor >> 16 & 0xff, endColor >> 16 & 0xff, percent);
        int g = getMiddleValue(startColor >> 8 & 0xff, endColor >> 8 & 0xff, percent);
        int b = getMiddleValue(startColor & 0xff, endColor & 0xff, percent);
        return Color.argb(a, r, g, b);
    }

    private int getMiddleValue(int start, int end, float percent) {
        return (int) (start + (end - start) * percent);
    }

    private float getDegreePosition(float scanDegree) {
        if (scanDegree < 0) {
            scanDegree = scanDegree + 360;
        } else if (scanDegree > 360) {
            scanDegree = scanDegree - 360;
        }
        float position = scanDegree / (float) 360;
        return position;
    }

    private void initializeShapeProperties() {
        mSize = Math.min(mHeight - mPadding * 2, mWidth - mPadding * 2);
        mCenterX = mWidth / 2;
        mCenterY = mHeight / 2;
        mRadius = mSize / 2;
        mCenterX = mWidth / 2;
        mCenterY = mHeight / 2;
        refresh();
    }

    public void setScanPeriod(int mScanPeriod) {
        this.mScanPeriod = mScanPeriod;
    }

    public void setPadding(int padding) {
        this.mPadding = padding;
        initializeShapeProperties();
    }

    private static class ColorPosition {
        float position = 0f;
        int color = 0;

        public ColorPosition(float position, int color) {
            this.position = position;
            this.color = color;
        }
    }
}
